package org.recast.RecastDemo.Source;

import org.draw.DrawingApplet;
import org.recast.Detour.Include.*;
import org.recast.Detour.Source.DetourNavMeshBuilderImpl;
import org.recast.Detour.Source.dtNavMeshImpl;
import org.recast.Detour.Source.dtNavMeshQueryImpl;
import org.recast.Recast.Include.*;
import org.recast.Recast.Source.RecastDump;
import org.recast.Recast.Source.RecastImpl;
import org.recast.RecastDemo.Include.*;

public class Sample_SoloMeshImpl extends Sample_SoloMesh
{
	//
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
//
// This software is provided 'as-is', without any express or implied
// warranty.  In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
//    misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//

//    #define _USE_MATH_DEFINES
//    #include <math.h>
//    #include <stdio.h>
//    #include <string.h>
//    #include "SDL.h"
//            #include "SDL_opengl.h"
//            #include "imgui.h"
//            #include "InputGeom.h"
//            #include "Sample.h"
//            #include "Sample_SoloMesh.h"
//            #include "Recast.h"
//            #include "RecastDebugDraw.h"
//            #include "RecastDump.h"
//            #include "DetourNavMesh.h"
//            #include "DetourNavMeshBuilder.h"
//            #include "DetourDebugDraw.h"
//            #include "NavMeshTesterTool.h"
//            #include "NavMeshPruneTool.h"
//            #include "OffMeshConnectionTool.h"
//            #include "ConvexVolumeTool.h"
//            #include "CrowdTool.h"
//
//            #ifdef WIN32
//    #	define snprintf _snprintf
//    #endif

	Recast recast = new RecastImpl();

	public Sample_SoloMeshImpl()
	{
		this.recast = new RecastImpl();
		m_keepInterResults = true;
//                m_totalBuildTimeMs(0),
//                m_triareas(0),
//                m_solid(0),
//                m_chf(0),
//                m_cset(0),
//                m_pmesh(0),
//                m_dmesh(0),
		m_drawMode = DrawMode.DRAWMODE_NAVMESH;
//        setTool(new NavMeshTesterTool);
	}
/*
	~Sample_SoloMesh()
    {
        cleanup();
    }*/

	public void cleanup()
	{
		m_triareas = null;
		m_solid = null;
		m_chf = null;
		m_cset = null;
		m_pmesh = null;
		m_dmesh = null;
//        m_navMesh = null;
//        delete [] m_triareas;
//        m_triareas = 0;
//        rcFreeHeightField(m_solid);
//        m_solid = 0;
//        rcFreeCompactHeightfield(m_chf);
//        m_chf = 0;
//        rcFreeContourSet(m_cset);
//        m_cset = 0;
//        rcFreePolyMesh(m_pmesh);
//        m_pmesh = 0;
//        rcFreePolyMeshDetail(m_dmesh);
//        m_dmesh = 0;
//        dtFreeNavMesh(m_navMesh);
//        m_navMesh = 0;
	}

	/*
		public void handleSettings()
		{
			Sample::handleCommonSettings();

			if (imguiCheck("Keep Itermediate Results", m_keepInterResults))
				m_keepInterResults = !m_keepInterResults;

			imguiSeparator();

			char msg[64];
			snprintf(msg, 64, "Build Time: %.1fms", m_totalBuildTimeMs);
			imguiLabel(msg);

			imguiSeparator();
		}

		public void handleTools()
		{
			int type = !m_tool ? TOOL_NONE : m_tool.type();

			if (imguiCheck("Test Navmesh", type == TOOL_NAVMESH_TESTER))
			{
				setTool(new NavMeshTesterTool);
			}
			if (imguiCheck("Prune Navmesh", type == TOOL_NAVMESH_PRUNE))
			{
				setTool(new NavMeshPruneTool);
			}
			if (imguiCheck("Create Off-Mesh Connections", type == TOOL_OFFMESH_CONNECTION))
			{
				setTool(new OffMeshConnectionTool);
			}
			if (imguiCheck("Create Convex Volumes", type == TOOL_CONVEX_VOLUME))
			{
				setTool(new ConvexVolumeTool);
			}
			if (imguiCheck("Create Crowds", type == TOOL_CROWD))
			{
				setTool(new CrowdTool);
			}

			imguiSeparatorLine();

			imguiIndent();

			if (m_tool)
				m_tool.handleMenu();

			imguiUnindent();

		}

		public void handleDebugMode()
		{
			// Check which modes are valid.
			bool valid[MAX_DRAWMODE];
			for (int i = 0; i < MAX_DRAWMODE; ++i)
				valid[i] = false;

			if (m_geom)
			{
				valid[DRAWMODE_NAVMESH] = m_navMesh != 0;
				valid[DRAWMODE_NAVMESH_TRANS] = m_navMesh != 0;
				valid[DRAWMODE_NAVMESH_BVTREE] = m_navMesh != 0;
				valid[DRAWMODE_NAVMESH_NODES] = m_navQuery != 0;
				valid[DRAWMODE_NAVMESH_INVIS] = m_navMesh != 0;
				valid[DRAWMODE_MESH] = true;
				valid[DRAWMODE_VOXELS] = m_solid != 0;
				valid[DRAWMODE_VOXELS_WALKABLE] = m_solid != 0;
				valid[DRAWMODE_COMPACT] = m_chf != 0;
				valid[DRAWMODE_COMPACT_DISTANCE] = m_chf != 0;
				valid[DRAWMODE_COMPACT_REGIONS] = m_chf != 0;
				valid[DRAWMODE_REGION_CONNECTIONS] = m_cset != 0;
				valid[DRAWMODE_RAW_CONTOURS] = m_cset != 0;
				valid[DRAWMODE_BOTH_CONTOURS] = m_cset != 0;
				valid[DRAWMODE_CONTOURS] = m_cset != 0;
				valid[DRAWMODE_POLYMESH] = m_pmesh != 0;
				valid[DRAWMODE_POLYMESH_DETAIL] = m_dmesh != 0;
			}

			int unavail = 0;
			for (int i = 0; i < MAX_DRAWMODE; ++i)
				if (!valid[i]) unavail++;

			if (unavail == MAX_DRAWMODE)
				return;

			imguiLabel("Draw");
			if (imguiCheck("Input Mesh", m_drawMode == DRAWMODE_MESH, valid[DRAWMODE_MESH]))
				m_drawMode = DRAWMODE_MESH;
			if (imguiCheck("Navmesh", m_drawMode == DRAWMODE_NAVMESH, valid[DRAWMODE_NAVMESH]))
				m_drawMode = DRAWMODE_NAVMESH;
			if (imguiCheck("Navmesh Invis", m_drawMode == DRAWMODE_NAVMESH_INVIS, valid[DRAWMODE_NAVMESH_INVIS]))
				m_drawMode = DRAWMODE_NAVMESH_INVIS;
			if (imguiCheck("Navmesh Trans", m_drawMode == DRAWMODE_NAVMESH_TRANS, valid[DRAWMODE_NAVMESH_TRANS]))
				m_drawMode = DRAWMODE_NAVMESH_TRANS;
			if (imguiCheck("Navmesh BVTree", m_drawMode == DRAWMODE_NAVMESH_BVTREE, valid[DRAWMODE_NAVMESH_BVTREE]))
				m_drawMode = DRAWMODE_NAVMESH_BVTREE;
			if (imguiCheck("Navmesh Nodes", m_drawMode == DRAWMODE_NAVMESH_NODES, valid[DRAWMODE_NAVMESH_NODES]))
				m_drawMode = DRAWMODE_NAVMESH_NODES;
			if (imguiCheck("Voxels", m_drawMode == DRAWMODE_VOXELS, valid[DRAWMODE_VOXELS]))
				m_drawMode = DRAWMODE_VOXELS;
			if (imguiCheck("Walkable Voxels", m_drawMode == DRAWMODE_VOXELS_WALKABLE, valid[DRAWMODE_VOXELS_WALKABLE]))
				m_drawMode = DRAWMODE_VOXELS_WALKABLE;
			if (imguiCheck("Compact", m_drawMode == DRAWMODE_COMPACT, valid[DRAWMODE_COMPACT]))
				m_drawMode = DRAWMODE_COMPACT;
			if (imguiCheck("Compact Distance", m_drawMode == DRAWMODE_COMPACT_DISTANCE, valid[DRAWMODE_COMPACT_DISTANCE]))
				m_drawMode = DRAWMODE_COMPACT_DISTANCE;
			if (imguiCheck("Compact Regions", m_drawMode == DRAWMODE_COMPACT_REGIONS, valid[DRAWMODE_COMPACT_REGIONS]))
				m_drawMode = DRAWMODE_COMPACT_REGIONS;
			if (imguiCheck("Region Connections", m_drawMode == DRAWMODE_REGION_CONNECTIONS, valid[DRAWMODE_REGION_CONNECTIONS]))
				m_drawMode = DRAWMODE_REGION_CONNECTIONS;
			if (imguiCheck("Raw Contours", m_drawMode == DRAWMODE_RAW_CONTOURS, valid[DRAWMODE_RAW_CONTOURS]))
				m_drawMode = DRAWMODE_RAW_CONTOURS;
			if (imguiCheck("Both Contours", m_drawMode == DRAWMODE_BOTH_CONTOURS, valid[DRAWMODE_BOTH_CONTOURS]))
				m_drawMode = DRAWMODE_BOTH_CONTOURS;
			if (imguiCheck("Contours", m_drawMode == DRAWMODE_CONTOURS, valid[DRAWMODE_CONTOURS]))
				m_drawMode = DRAWMODE_CONTOURS;
			if (imguiCheck("Poly Mesh", m_drawMode == DRAWMODE_POLYMESH, valid[DRAWMODE_POLYMESH]))
				m_drawMode = DRAWMODE_POLYMESH;
			if (imguiCheck("Poly Mesh Detail", m_drawMode == DRAWMODE_POLYMESH_DETAIL, valid[DRAWMODE_POLYMESH_DETAIL]))
				m_drawMode = DRAWMODE_POLYMESH_DETAIL;

			if (unavail)
			{
				imguiValue("Tick 'Keep Itermediate Results'");
				imguiValue("to see more debug mode options.");
			}
		}



		public void handleRenderOverlay(double[] proj, double[] model, int[] view)
		{
			if (m_tool)
				m_tool.handleRenderOverlay(proj, model, view);
			renderOverlayToolStates(proj, model, view);
		}

	*/
	public void handleRender(DrawingApplet drawing)
	{
//        if (!m_geom || !m_geom.getMesh())
//            return;

//        DebugDrawGL dd;

//        glEnable(GL_FOG);
//        glDepthMask(GL_TRUE);

		float texScale = 1.0f / (m_cellSize * 10.0f);

        /*if (m_drawMode != DRAWMODE_NAVMESH_TRANS)
        {
            // Draw mesh
            duDebugDrawTriMeshSlope(&dd, m_geom.getMesh().getVerts(), m_geom.getMesh().getVertCount(),
                m_geom.getMesh().getTris(), m_geom.getMesh().getNormals(), m_geom.getMesh().getTriCount(),
                m_agentMaxSlope, texScale);
            m_geom.drawOffMeshConnections(&dd);
        }*/

//        glDisable(GL_FOG);
//        glDepthMask(GL_FALSE);

		// Draw bounds
		float[] bmin = m_geom.getMeshBoundsMin();
		float[] bmax = m_geom.getMeshBoundsMax();

        /*duDebugDrawBoxWire(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f);
        dd.begin(DU_DRAW_POINTS, 5.0f);
        dd.vertex(bmin[0],bmin[1],bmin[2],duRGBA(255,255,255,128));
        dd.end();*/

		if (/*m_navMesh && m_navQuery &&*/
//                (m_drawMode == DRAWMODE_NAVMESH ||
			m_drawMode == DrawMode.DRAWMODE_NAVMESH_TRANS// ||
//                        m_drawMode == DRAWMODE_NAVMESH_BVTREE ||
//                        m_drawMode == DRAWMODE_NAVMESH_NODES ||
//                        m_drawMode == DRAWMODE_NAVMESH_INVIS)
			)
		{
//            if (m_drawMode != DRAWMODE_NAVMESH_INVIS)
                /*duDebugDrawNavMeshWithClosedList(&dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags);*/
//            if (m_drawMode == DRAWMODE_NAVMESH_BVTREE)
//                duDebugDrawNavMeshBVTree(&dd, *m_navMesh);
//            if (m_drawMode == DRAWMODE_NAVMESH_NODES)
//                duDebugDrawNavMeshNodes(&dd, *m_navQuery);
            /*duDebugDrawNavMeshPolysWithFlags(&dd, *m_navMesh, SAMPLE_POLYFLAGS_DISABLED, duRGBA(0,0,0,128));*/
		}

//        glDepthMask(GL_TRUE);

//        if (m_dmesh && m_drawMode == DRAWMODE_POLYMESH_DETAIL)
//        {
//            glDepthMask(GL_FALSE);
//            duDebugDrawPolyMeshDetail(&dd, *m_dmesh);
//            glDepthMask(GL_TRUE);
//        }

//        m_geom.drawConvexVolumes(&dd);

//        if (m_tool)
//            m_tool.handleRender();
//        renderToolStates();

//        glDepthMask(GL_TRUE);
	}

	public void handleMeshChanged(InputGeom geom)
	{
		super.handleMeshChanged(geom);

        /*dtFreeNavMesh(m_navMesh);
        m_navMesh = 0;

        if (m_tool)
        {
            m_tool.reset();
            m_tool.init(this);
        }
        resetToolStates();
        initToolStates(this);*/
	}

	public boolean handleBuild()
	{
        /*if (!m_geom || !m_geom.getMesh())
        {
            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Input mesh is not specified.");
            return false;
        }*/

		cleanup();

		float[] bmin = m_geom.getMeshBoundsMin();
		float[] bmax = m_geom.getMeshBoundsMax();
		float[] verts = m_geom.getMesh().getVerts();
		int nverts = m_geom.getMesh().getVertCount();
		int[] tris = m_geom.getMesh().getTris();
		int ntris = m_geom.getMesh().getTriCount();

		//
		// Step 1. Initialize build config.
		//

		// Init build configuration from GUI
//        memset(&m_cfg, 0, sizeof(m_cfg));
		m_cfg = new rcConfig();
		m_cfg.cs = m_cellSize;
		m_cfg.ch = m_cellHeight;
		m_cfg.walkableSlopeAngle = m_agentMaxSlope;
		m_cfg.walkableHeight = (int)Math.ceil(m_agentHeight / m_cfg.ch);
		m_cfg.walkableClimb = (int)Math.floor(m_agentMaxClimb / m_cfg.ch);
		m_cfg.walkableRadius = (int)Math.ceil(m_agentRadius / m_cfg.cs);
		m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize);
		m_cfg.maxSimplificationError = m_edgeMaxError;
		m_cfg.minRegionArea = (int)Recast.rcSqr(m_regionMinSize);        // Note: area = size*size
		m_cfg.mergeRegionArea = (int)Recast.rcSqr(m_regionMergeSize);    // Note: area = size*size
		m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
		m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
		m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;

		// Set the area where the navigation will be build.
		// Here the bounds of the input mesh are used, but the
		// area could be specified by an user defined box, etc.
		InputGeom.rcVcopy(m_cfg.bmin, bmin);
		InputGeom.rcVcopy(m_cfg.bmax, bmax);
		int tmpW[] = new int[]{m_cfg.width};
		int tmpH[] = new int[]{m_cfg.height};
		recast.rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, tmpW, tmpH);
		m_cfg.width = tmpW[0];
		m_cfg.height = tmpH[0];

		// Reset build times gathering.
		m_ctx.resetTimers();

		// Start the build process.
		m_ctx.startTimer(rcTimerLabel.RC_TIMER_TOTAL);

		m_ctx.log(rcLogCategory.RC_LOG_PROGRESS, "Building navigation:");
		m_ctx.log(rcLogCategory.RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height);
		m_ctx.log(rcLogCategory.RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", nverts / 1000.0f, ntris / 1000.0f);

		//
		// Step 2. Rasterize input polygon soup.
		//

		// Allocate voxel heightfield where we rasterize our input data to.
		m_solid = new rcHeightfield();
        /*if (!m_solid)
        {
            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
            return false;
        }*/
		if (!recast.rcCreateHeightfield(m_ctx, m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
		{
			m_ctx.log(rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield.");
			return false;
		}

		// Allocate array that can hold triangle area types.
		// If you have multiple meshes you need to process, allocate
		// and array which can hold the max number of triangles you need to process.
		m_triareas = new char[ntris];
        /*if (!m_triareas)
        {
            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (%d).", ntris);
            return false;
        }*/

		// Find triangles which are walkable based on their slope and rasterize them.
		// If your input data is multiple meshes, you can transform them here, calculate
		// the are type for each of the meshes and rasterize them.
//        memset(m_triareas, 0, ntris*sizeof(unsigned char));
		recast.rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas);
		recast.rcRasterizeTriangles(m_ctx, verts, nverts, tris, m_triareas, ntris, m_solid, m_cfg.walkableClimb);

		if (!m_keepInterResults)
		{
			m_triareas = null;
//            delete [] m_triareas;
//            m_triareas = 0;
		}

		//
		// Step 3. Filter walkables surfaces.
		//

		// Once all geoemtry is rasterized, we do initial pass of filtering to
		// remove unwanted overhangs caused by the conservative rasterization
		// as well as filter spans where the character cannot possibly stand.
		recast.rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, m_solid);
		recast.rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid);
		recast.rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, m_solid);

		//
		// Step 4. Partition walkable surface to simple regions.
		//

		// Compact the heightfield so that it is faster to handle from now on.
		// This will result more cache coherent data as well as the neighbours
		// between walkable cells will be calculated.
		m_chf = new rcCompactHeightfield();//rcAllocCompactHeightfield();
        /*if (!m_chf)
        {
            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
            return false;
        }*/
		if (!recast.rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid, m_chf))
		{
			m_ctx.log(rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
			return false;
		}

		if (!m_keepInterResults)
		{
//            recast.rcFreeHeightField(m_solid);
			m_solid = null;
		}

		// Erode the walkable area by agent radius.
		if (!recast.rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, m_chf))
		{
			m_ctx.log(rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not erode.");
			return false;
		}

		// (Optional) Mark areas.
		InputGeom.ConvexVolume[] vols = m_geom.getConvexVolumes();
		for (int i = 0; i < m_geom.getConvexVolumeCount(); ++i)
			recast.rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (char)vols[i].area, m_chf);

		if (m_monotonePartitioning)
		{
			// Partition the walkable surface into simple regions without holes.
			// Monotone partitioning does not need distancefield.
			if (!recast.rcBuildRegionsMonotone(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
			{
				m_ctx.log(rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
				return false;
			}
		}
		else
		{
			// Prepare for region partitioning, by calculating distance field along the walkable surface.
			if (!recast.rcBuildDistanceField(m_ctx, m_chf))
			{
				m_ctx.log(rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
				return false;
			}

			// Partition the walkable surface into simple regions without holes.
			if (!recast.rcBuildRegions(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
			{
				m_ctx.log(rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
				return false;
			}
		}

		//
		// Step 5. Trace and simplify region contours.
		//

		// Create contours.
		m_cset = new rcContourSet();//rcAllocContourSet();
        /*if (!m_cset)
        {
            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
            return false;
        }*/
		if (!recast.rcBuildContours(m_ctx, m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, m_cset))
		{
//            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Could not create contours.");
			return false;
		}

		//
		// Step 6. Build polygons mesh from contours.
		//

		// Build polygon navmesh from the contours.
		m_pmesh = new rcPolyMesh();//rcAllocPolyMesh();
        /*if (!m_pmesh)
        {
            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
            return false;
        }*/
		if (!recast.rcBuildPolyMesh(m_ctx, m_cset, m_cfg.maxVertsPerPoly, m_pmesh))
		{
//            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
			return false;
		}

		//
		// Step 7. Create detail mesh which allows to access approximate height on each polygon.
		//

		m_dmesh = new rcPolyMeshDetail();//rcAllocPolyMeshDetail();
        /*if (!m_dmesh)
        {
            m_ctx.log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
            return false;
        }*/

		if (!recast.rcBuildPolyMeshDetail(m_ctx, m_pmesh, m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, m_dmesh))
		{
			m_ctx.log(rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
			return false;
		}
		assert m_dmesh.ntris == 292;
		assert m_dmesh.nmeshes == 120;
		assert m_dmesh.nverts == 515;
		if (!m_keepInterResults)
		{
//            recast.rcFreeCompactHeightfield(m_chf);
//            m_chf = 0;
//            rcFreeContourSet(m_cset);
//            m_cset = 0;
		}

		// At this point the navigation mesh data is ready, you can access it from m_pmesh.
		// See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.

		//
		// (Optional) Step 8. Create Detour data from Recast poly mesh.
		//

		// The GUI may allow more max points per polygon than Detour can handle.
		// Only build the detour navmesh if we do not exceed the limit.
		if (m_cfg.maxVertsPerPoly <= DetourNavMesh.DT_VERTS_PER_POLYGON)
		{
//            char[] navData = 0;
//            int navDataSize = 0;
//			unsigned char* navData = 0;
			dtMeshHeader header = new dtMeshHeader();
			dtMeshTile meshTile = new dtMeshTile();
			meshTile.header = header;

			// Update poly flags from areas.
			for (int i = 0; i < m_pmesh.npolys; ++i)
			{
				if (m_pmesh.areas[i] == Recast.RC_WALKABLE_AREA)
					m_pmesh.areas[i] = SamplePolyAreas.SAMPLE_POLYAREA_GROUND.v;

				if (m_pmesh.areas[i] == SamplePolyAreas.SAMPLE_POLYAREA_GROUND.v ||
					m_pmesh.areas[i] == SamplePolyAreas.SAMPLE_POLYAREA_GRASS.v ||
					m_pmesh.areas[i] == SamplePolyAreas.SAMPLE_POLYAREA_ROAD.v)
				{
					m_pmesh.flags[i] = SamplePolyFlags.SAMPLE_POLYFLAGS_WALK.v;
				}
				else if (m_pmesh.areas[i] == SamplePolyAreas.SAMPLE_POLYAREA_WATER.v)
				{
					m_pmesh.flags[i] = SamplePolyFlags.SAMPLE_POLYFLAGS_SWIM.v;
				}
				else if (m_pmesh.areas[i] == SamplePolyAreas.SAMPLE_POLYAREA_DOOR.v)
				{
					m_pmesh.flags[i] = SamplePolyFlags.SAMPLE_POLYFLAGS_WALK.v | SamplePolyFlags.SAMPLE_POLYFLAGS_DOOR.v;
				}
			}

			dtNavMeshCreateParams params = new dtNavMeshCreateParams();
//            memset(&params, 0, sizeof(params));
			params.verts = m_pmesh.verts;
			params.vertCount = m_pmesh.nverts;
			params.polys = m_pmesh.polys;
			params.polyAreas = m_pmesh.areas;
			params.polyFlags = m_pmesh.flags;
			params.polyCount = m_pmesh.npolys;
			params.nvp = m_pmesh.nvp;
			params.detailMeshes = m_dmesh.meshes;
			params.detailVerts = m_dmesh.verts;
			params.detailVertsCount = m_dmesh.nverts;
			params.detailTris = m_dmesh.tris;
			params.detailTriCount = m_dmesh.ntris;
			params.offMeshConVerts = m_geom.getOffMeshConnectionVerts();
			params.offMeshConRad = m_geom.getOffMeshConnectionRads();
			params.offMeshConDir = m_geom.getOffMeshConnectionDirs();
			params.offMeshConAreas = m_geom.getOffMeshConnectionAreas();
			params.offMeshConFlags = m_geom.getOffMeshConnectionFlags();
			params.offMeshConUserID = m_geom.getOffMeshConnectionId();
			params.offMeshConCount = m_geom.getOffMeshConnectionCount();
			params.walkableHeight = m_agentHeight;
			params.walkableRadius = m_agentRadius;
			params.walkableClimb = m_agentMaxClimb;
			InputGeom.rcVcopy(params.bmin, m_pmesh.bmin);
			InputGeom.rcVcopy(params.bmax, m_pmesh.bmax);
			params.cs = m_cfg.cs;
			params.ch = m_cfg.ch;
			params.buildBvTree = true;

			if (!new DetourNavMeshBuilderImpl().dtCreateNavMeshData(params, meshTile))
			{
				m_ctx.log(rcLogCategory.RC_LOG_ERROR, "Could not build Detour navmesh.");
				return false;
			}

			m_navMesh = new dtNavMeshImpl();
			/*if (!m_navMesh)
			{
				dtFree(navData);
				m_ctx->log(RC_LOG_ERROR, "Could not create Detour navmesh");
				return false;
			}*/

			dtStatus status;

			status = m_navMesh.init(meshTile, DetourNavMesh.dtTileFlags.DT_TILE_FREE_DATA);
			if (dtStatus.dtStatusFailed(status))
			{
//				dtFree(navData);
				m_ctx.log(rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh");
				return false;
			}

			m_navQuery = new dtNavMeshQueryImpl();
			status = m_navQuery.init(m_navMesh, 2048);
			if (dtStatus.dtStatusFailed(status))
			{
				m_ctx.log(rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh query");
				return false;
			}
		}

		m_ctx.stopTimer(rcTimerLabel.RC_TIMER_TOTAL);

		// Show performance stats.
		new RecastDump().duLogBuildTimes(m_ctx, m_ctx.getAccumulatedTime(rcTimerLabel.RC_TIMER_TOTAL));
		m_ctx.log(rcLogCategory.RC_LOG_PROGRESS, ">> Polymesh: %d vertices  %d polygons", m_pmesh.nverts, m_pmesh.npolys);

		m_totalBuildTimeMs = m_ctx.getAccumulatedTime(rcTimerLabel.RC_TIMER_TOTAL) / 1000.0f;

//		handleClick(rays, pos, processHitTestShift);

//        if (m_tool != null)
//            m_tool.init(this);
//        initToolStates(this);

		return true;
	}

}
